/** GeoVisual.java
 * 
 * Provides a visualization panel for Geometric Series.
 *
 * Author: Ralph Gootee Copyright (c) 2007
 * GNU License
 *
 **/

import java.awt.*;
import javax.swing.*;

import javax.swing.event.*;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

//------------------------------------------------------------------------------
 class GeoVisual extends JPanel implements MouseListener{
	
	public int ELLIPSE=0;
	public int RECTANGLE=1;

	private double a;
	private double r;
	private int n;
	
	private int selectedIndex;

	private double [] points;
	
	private int x0,y0;
			
	/** Provides the base gradient color **/
	private Color baseColor;

	/** Provides the selection color, for highlighting. **/
	private Color selectColor;

	/** Shape for the visual, set with ELLIPS, etc **/
	private int shape;

	//------------------------------------------------------------------------------
	public GeoVisual(){
			
		System.out.println("Constructing GeoVisual,,,");

		addMouseListener(this);

		int w =300;
		int h = 300;

		setPreferredSize(new Dimension(w,h));
		setMinimumSize(new Dimension(w,h));
		setMaximumSize(new Dimension(w,h));
			
		a = .5;
		r = 1;
		n= 10;
		selectedIndex=-1;
		shape=0;

		baseColor = new Color(255,255,255);
		selectColor = new Color(255,255,0);

		constructPoints();

 		int x0 = (int)Math.floor(w/2.0);
   		int y0 = (int)Math.floor(h/2.0); 	
		setOrigin(x0,y0);
	}
		
	//------------------------------------------------------------------------------
	public Color getBaseColor(){ return baseColor;}
		
	//------------------------------------------------------------------------------
	public void setBaseColor(Color b_){ 
		baseColor = b_;	
		repaint();
	}

	//------------------------------------------------------------------------------
	public void setOrigin(int x,int y){ 
		x0=x;
		y0=y;
		repaint(); 
	}

	//------------------------------------------------------------------------------
	public void setN(int n_){
		n = n_;
		constructPoints();
		repaint();
	}
	
	//------------------------------------------------------------------------------
	public int getN(){return n;}

	//------------------------------------------------------------------------------
	public void setA(double a_){
		a = a_;
		constructPoints();
		repaint();
	}
 	
	//------------------------------------------------------------------------------
	public double getA(){ return a;}

	
	//------------------------------------------------------------------------------
	public void setR(double r_){
		r = r_;
		constructPoints();
		repaint();
	}
	
	//------------------------------------------------------------------------------
	public double getR(){ return r;}

	//------------------------------------------------------------------------------
	public void setSelectedIndex(int sel){ 
		selectedIndex = sel; 
		repaint();
	}

	//------------------------------------------------------------------------------
	public void setShape(int shape_){ 
		shape= shape_;
		repaint();
	}

	//------------------------------------------------------------------------------
 	public void mousePressed(MouseEvent e) { }
    public void mouseReleased(MouseEvent e) { }
    public void mouseEntered(MouseEvent e) {}
	public void mouseExited(MouseEvent e) {}

	//------------------------------------------------------------------------------
   	public void mouseClicked(MouseEvent e) {
    	setOrigin(e.getX(),e.getY());
	}
		
	//------------------------------------------------------------------------------
	public void paint( Graphics g ) {
       
		// =Edge Passing
		int PADDING =15;

   		int h = getSize().height - 2*PADDING;
   		int w = getSize().width  - 2*PADDING; 	

		//Clear the old stuff
		g.setColor(Color.gray);

		// Extra fill, seems to bug out sometimes :(
		g.fillRect(0,0,getSize().height*2,getSize().width*2);

		double max=max(points);
	
		double xTrans = w / max;	
		double yTrans = h / max;	

		// This might need to be adjusted depending on the sign of a
		int nn = points.length-1;
		if(a >0) nn++;

		for(int i=0;i<nn;i++){

			int index=i;

			if(a > 0){ index = points.length - i -1;}

			double p = 1 - index/(double)points.length;		

			int sx = (int)Math.floor(points[index] * xTrans);
			int sy = (int)Math.floor(points[index] * yTrans);
				
			int ox = (int)Math.floor((sx)/2);
			int oy = (int)Math.floor((sy)/2);
	
			Color c;

			if(index != selectedIndex){
				 c = new Color(	(int)Math.floor(baseColor.getRed()*p),
								(int)Math.floor(baseColor.getGreen()*p),
								(int)Math.floor(baseColor.getBlue()*p));
			}else{
				c = selectColor;
			}

			g.setColor(c);
			
			if(shape == ELLIPSE){
				g.fillOval(x0-ox,y0-oy,sx,sy);
			}else if(shape == RECTANGLE){
				g.fillRect(x0-ox,y0-oy,sx,sy);
			}
		}
	}
	
	//------------------------------------------------------------------------------
	private void constructPoints(){
		points = new double[n];	
		double val =0;

		for(int i=0;i<n;i++){
			val += r*Math.pow(a,i);		
			points[i] = val;
		}
	}

	//------------------------------------------------------------------------------
	public double [] getPoints(){ return points;}

	//------------------------------------------------------------------------------
	public double getConv(){
		if(1 > a && a > -1){
			return (r/(1-a));
		}else{
			return Double.POSITIVE_INFINITY;
		}
	}
	
	//===================================================== max
	public static double max(double[] t) {
    	double maximum = t[0];   // start with the first value
   		for (int i=1; i<t.length; i++) {
        	if (t[i] > maximum) {
            	maximum = t[i];   // new maximum
        	}
    	}
    	return maximum;
	}//end method max


}

